#include <shlwapi.h>
#include "xstring.h"
#include "httpserver.h"
#include "common.h"
#include <cstdlib>

#define URL L"http://127.0.0.1:8888/"

enum WebBrowserType
{
    WBT_None = 0,
    WBT_CHROME,
    WBT_MSEDGE,
    WBT_EPIC,
    WBT_VIVALDI,
    WBT_BRAVE,
    WBT_BROWSER,
    WBT_FIREFOX
};


WebBrowserType find_webbrowser(LPWSTR path, size_t size);
void make_webbrowser_args(wstring &args, LPWSTR userDataPath, LPCWSTR path, WebBrowserType wbt, LPCWSTR url);
void RemoveTree(LPCWSTR path);


void start()
{
    WebBrowserType wbt;
    WCHAR path[MAX_PATH];

    wbt = find_webbrowser(path, MAX_PATH);
    if(wbt)
    {
        bool hasExit = false;
        HttpServer httpserver;
        if(httpserver.init(URL))
        {
            WCHAR userDataPath[MAX_PATH];
            wstring args;
            STARTUPINFOW si = {sizeof(STARTUPINFOW)};
            PROCESS_INFORMATION pi;

            make_webbrowser_args(args, userDataPath, path, wbt, URL);
            if(CreateProcessW(path, args, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
            {
                httpserver.onReceive(hasExit, pi.hProcess);
                if(!hasExit)
                    WaitForSingleObject(pi.hProcess, INFINITE);
                CloseHandle(pi.hThread);
                CloseHandle(pi.hProcess);
            }
            RemoveTree(userDataPath);
        }
    }
    ExitProcess(0);
}

WebBrowserType find_webbrowser(LPWSTR path, size_t size)
{
    HKEY root_hkey[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
    LPCWSTR webbrowser_names[] =
    {
        L"chrome.exe",
        L"msedge.exe",
        L"epic.exe",
        L"vivaldi.exe",
        L"brave.exe",
        L"browser.exe",
        L"firefox.exe"
    };
#define SUBKEY_STR L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"
    WCHAR subkey[_countof(SUBKEY_STR) + 20];
    memcpy(subkey, SUBKEY_STR, sizeof(SUBKEY_STR));
    for(size_t i = 0; i < _countof(root_hkey); i++)
    {
        for(size_t j = 0; j < _countof(webbrowser_names); j++)
        {
            DWORD dwSize = size;
            wcscpy_s(subkey + _countof(SUBKEY_STR) - 1, 21, webbrowser_names[j]);
            if(ERROR_SUCCESS != RegGetValueW(root_hkey[i], subkey, NULL, RRF_RT_REG_SZ, NULL, path, &dwSize))
                continue;
            return WebBrowserType(j + 1);
        }
    }
    return WBT_None;
}

void make_webbrowser_args(wstring &args, LPWSTR userDataPath, LPCWSTR path, WebBrowserType wbt, LPCWSTR url)
{
    GetModuleFileNameW(NULL, userDataPath, MAX_PATH);
    *PathFindExtensionW(userDataPath) = 0;
    CreateDirectoryW(userDataPath, NULL);
    if(wbt != WBT_FIREFOX)
    {
        args.Format(
                L"\"%s\" --user-data-dir=\"%s\""
                L" --no-first-run"
                L" --no-proxy-server"
                L" --safe-mode"
                L" --disable-extensions"
                L" --disable-background-mode"
                L" --disable-plugins"
                L" --disable-plugins-discovery"
                L" --disable-translate"
                L" --disable-features=Translate"
                L" --bwsi"
                L" --disable-sync"
                L" --disable-sync-preferences"
                L" --disable-component-update"
                L" --allow-insecure-localhost"
                L" --disable-breakpad"
                /*
                 * kiosk_mode: --chrome-frame --kiosk
                 * Hide Mode: --headless --headless=new
                 * Window Size: --window-size=%u,%u
                 * Window Position: --window-position=%u,%u
                 */
                L" --app=%s",
            path, userDataPath, url);
    }
    else
    {
        args.Format(
                L"\"%s\" -P WebUI"
                L" -purgecaches"
                /*
                 * kiosk_mode: -kiosk
                 * Hide Mode: -headless
                 * Window Size: -width %u -height %u
                 */
                L" -new-window %s",
                path, url);
    }
}

void RemoveTree(LPCWSTR path)
{
    WIN32_FIND_DATAW wfd;
    HANDLE hFind;

    wstring spath;
    spath.Format(L"%s\\*", path);
    hFind = FindFirstFileW(spath, &wfd);
    if (hFind == INVALID_HANDLE_VALUE) 
        return;
    do
    {
        if(!wcscmp(wfd.cFileName, L"."))
            continue;
        if(!wcscmp(wfd.cFileName, L".."))
            continue;
        spath.Format(L"%s\\%s", path, wfd.cFileName);
        if(wfd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
            RemoveTree(spath);
        else
            DeleteFileW(spath);
    }while(FindNextFileW(hFind, &wfd));
    FindClose(hFind);
    RemoveDirectoryW(path);
}
